package me.kevinwalker.core.utils;

import me.kevinwalker.core.handler.BaseMongoDBInvocationHandler;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;

/**
 * 代理类对象实例工具
 */
public class MongoDBProxyUtil {

    /**
     * 得到类的代理类对象实例
     *
     * @param classes 接口对象
     * @return 代理类对象实例
     */
    public static Object getInstance(Class classes) {
        BaseMongoDBInvocationHandler baseMongoDBInvocationHandler = new BaseMongoDBInvocationHandler(classes);
        return Proxy.newProxyInstance(classes.getClassLoader(), new Class<?>[]{classes}, baseMongoDBInvocationHandler);
    }

    /**
     * 根据子类获取父接口指定的泛型类型，未找到指定泛型时将返回空
     *
     * @param subClass             子类类型
     * @param targetInterfaceClass 父接口类型
     * @param genericIndex         泛型下标
     * @return 泛型类型
     */
    public static Class<?> getInterfaceGenericClass(Class<?> subClass, Class<?> targetInterfaceClass, int genericIndex) {
        if (subClass == null || targetInterfaceClass == null || genericIndex < 0) {
            return null;
        }
        Class<?> clazz = subClass;
        while (clazz != null && clazz != Object.class) {
            Type[] types = clazz.getGenericInterfaces();
            for (Type type : types) {
                if (type.getTypeName().contains(targetInterfaceClass.getName())) {
                    Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
                    if (genericIndex >= typeArguments.length) {
                        return null;
                    }
                    Type typeArgument = typeArguments[genericIndex];
                    if (typeArgument instanceof Class) {
                        return (Class<?>) typeArgument;
                    }
                    return null;
                }
            }
            Class<?>[] interfaces = clazz.getInterfaces();
            for (Class<?> inter : interfaces) {
                Class<?> result = getInterfaceGenericClass(inter, targetInterfaceClass, genericIndex);
                if (result != null) {
                    return result;
                }
            }
            clazz = clazz.getSuperclass();
        }
        return null;
    }
}
